<?php

declare(strict_types=1);

namespace App\Admin;

use App\Entity\AdminUser;
use App\Entity\Page;
use App\Entity\PageCategory;
use App\Entity\PageTag;
use App\Enum\LogTypeEnum;
use App\Enum\PageEnum;
use App\Form\Type\PagePublishFieldType;
use App\Form\Type\ThumbnailItemFieldType;
use App\Message\SubscribePage;
use App\Utils\Helper\GetterHelper;
use App\Utils\Helper\LogHelper;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Object\Metadata;
use Sonata\AdminBundle\Route\RouteCollection;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\DoctrineORMAdminBundle\Filter\CallbackFilter;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Security\Core\Security;

final class PageAdmin extends AbstractAdmin {
    protected $baseRouteName = 'admin_page';
    protected $baseRoutePattern = 'page';
    protected $maxPageLinks = 10;
    protected $security;
    protected $bus;

    public function __construct ($code, $class, $baseControllerName, Security $security, MessageBusInterface $bus) {
        parent::__construct($code, $class, $baseControllerName);
        $this->security = $security;
        $this->bus = $bus;
    }

    protected function configureDefaultSortValues (array &$sortValues) {
        $sortValues['_page'] = 1;
        $sortValues['_per_page'] = 32;
        $sortValues['_sort_order'] = 'DESC';
        $sortValues['_sort_by'] = 'id';
    }

    public function toString ($object) {
        return $object instanceof Page ? $object->getTitle() : '文章';
    }

    protected function configureDatagridFilters (DatagridMapper $datagridMapper): void {
        $datagridMapper
            ->add('title', null, [
                'label'       => '标题',
                'show_filter' => true,
            ])
            ->add('page_category_id', 'doctrine_orm_choice', [
                'label'       => '类别',
                'show_filter' => true,
            ], ChoiceType::class, [
                'choices' => array_flip(GetterHelper::getEntityManager()->getRepository(PageCategory::class)->findAllToArray()),
            ])
            ->add('page_tags', CallbackFilter::class, [
                'label'       => '标签',
                'callback'    => [$this, 'getPageTagsFilter'],
            ], ChoiceType::class, [
                'choices'  => array_flip(GetterHelper::getEntityManager()->getRepository(PageTag::class)->findAllToArray()),
                'multiple' => true,
            ])
            ->add('status', 'doctrine_orm_choice', [
                'label' => '发布',
            ], ChoiceType::class, [
                'choices' => [
                    '是' => 1,
                    '否' => 0,
                ],
            ])
            ->add('is_top', null, ['label' => '置顶'])
            ->add('is_recommend', null, ['label' => '推荐'])
            ->add('is_comment', null, ['label' => '评论'])
            ->add('admin_user_id', 'doctrine_orm_choice', [
                'label' => '创建人',
            ], ChoiceType::class, [
                'choices' => array_flip(GetterHelper::getEntityManager()->getRepository(AdminUser::class)->findAllToArray()),
            ])
            ->add('created_at', CallbackFilter::class, [
                'label'    => '创建日期',
                'callback' => [$this, 'getCreatedAtFilter'],
            ], null, [
                'attr' => [
                    'readonly' => 'readonly',
                    'style'    => 'background-color: #fff',
                ],
            ])
            ->add('publish_time', CallbackFilter::class, [
                'label'    => '发布日期',
                'callback' => [$this, 'getPublishTimeFilter'],
                'show_filter' => true,
            ], null, [
                'attr' => [
                    'readonly' => 'readonly',
                    'style'    => 'background-color: #fff',
                ],
            ]);
    }

    public function getPageTagsFilter ($queryBuilder, $alias, $field, $value) {
        if (!$value['value']) {
            return false;
        }

        $tags = implode(',', $value['value']);
        $queryBuilder->andWhere($queryBuilder->expr()->andX("JSON_CONTAINS(".$alias.".".$field.", '[".$tags."]', '$') = 1"));

        return true;
    }

    public function getCreatedAtFilter ($queryBuilder, $alias, $field, $value) {
        if (!$value['value']) {
            return false;
        }

        $dataArr = explode(' - ', $value['value']);
        if (count($dataArr) != 2) {
            return false;
        }

        $start = $dataArr[0].' 00:00:00';
        $end = $dataArr[1].' 23:59:59';
        $queryBuilder->andWhere($queryBuilder->expr()->between($alias.'.'.$field, "'".$start."'", "'".$end."'"));

        return true;
    }

    public function getPublishTimeFilter ($queryBuilder, $alias, $field, $value) {
        if (!$value['value']) {
            return false;
        }

        $dataArr = explode(' - ', $value['value']);
        if (count($dataArr) != 2) {
            return false;
        }

        $start = $dataArr[0].' 00:00:00';
        $end = $dataArr[1].' 23:59:59';
        $queryBuilder->andWhere($queryBuilder->expr()->between($alias.'.'.$field, "'".$start."'", "'".$end."'"));

        return true;
    }

    protected function configureListFields (ListMapper $listMapper): void {
        $listMapper
            ->addIdentifier('title', null, [
                'label'        => '标题',
                'header_style' => 'width: 40%; text-align: left',
                'row_align'    => 'left',
            ])
            ->add('page_category_id', null, [
                'label'         => '类别',
                'page_category' => GetterHelper::getEntityManager()->getRepository(PageCategory::class)->findAllToArray(),
                'template'      => 'backend/public/list_page_category_id.html.twig',
            ])
            ->add('page_tags', null, [
                'label'        => '标签',
                'header_style' => 'width: 12%; text-align: left',
                'row_align'    => 'left',
                'page_tags'    => GetterHelper::getEntityManager()->getRepository(PageTag::class)->findAllToArray(),
                'template'     => 'backend/page/list_page_tags.html.twig',
            ])
            ->add('page_like', null, ['label' => '点赞量'])
            ->add('page_view', null, ['label' => '阅读量'])
            ->add('page_comment', null, [
                'label'     => '评论',
                'row_align' => 'right',
                'template'  => 'backend/page/list_page_comment.html.twig',
            ])
            ->add('admin_user_id', null, [
                'label'       => '创建人',
                'admin_users' => GetterHelper::getEntityManager()->getRepository(AdminUser::class)->findAllToArray(),
                'template'    => 'backend/public/list_admin_user_id.html.twig',
            ])
            ->add('status', null, [
                'label'    => '发布',
                'template' => 'backend/page/list_status.html.twig',
            ])
            ->add('publish_time', null, [
                'format'       => 'Y-m-d H:i:s',
                'timezone'     => 'PRC',
                'label'        => '发布时间',
                'header_style' => 'width: 15%; text-align: center',
                'row_align'    => 'center',
            ]);
    }

    protected function configureFormFields (FormMapper $formMapper): void {
        $formMapper
            ->with('基础', ['class' => 'col-md-8'])
            ->add('title', null, ['label' => '标题'])
            ->add('summary', TextareaType::class, [
                'label'    => '摘要',
                'required' => false,
                'attr'     => ['style' => 'resize: vertical', 'maxlength' => 400, 'rows' => 4],
            ])
            ->add('content', null, [
                'label' => '内容',
            ])
            ->end()
            ->with('相关', ['class' => 'col-md-4'])
            ->add('page_category_id', ChoiceType::class, [
                'label'    => '类别',
                'choices'  => array_flip(GetterHelper::getEntityManager()->getRepository(PageCategory::class)->findAllToArray()),
                'required' => true,
            ])
            ->add('page_tags', ChoiceType::class, [
                'label'    => '标签',
                'choices'  => array_flip(GetterHelper::getEntityManager()->getRepository(PageTag::class)->findAllToArray()),
                'multiple' => true,
                'required' => false,
            ])
            ->add('thumbnail_item', ThumbnailItemFieldType::class, ['label' => '缩略图'])
            ->add('is_top', null, [
                'label' => '设为置顶',
                'help'  => '置顶文章只能有一篇，新设置的文章会顶掉之前的置顶文章',
            ])
            ->add('is_recommend', null, [
                'label' => '设为推荐',
                'help'  => '该文章将会出现在首页幻灯处展示',
            ])
            ->add('is_comment', null, [
                'label' => '开启评论',
                'help'  => '开启之后该文章将接受用户评论',
            ])
            ->add('page_publish', PagePublishFieldType::class, [
                'label' => '发布状态',
            ])
            ->end()
            ->with('SEO', ['class' => 'col-md-4 float-right'])
            ->add('seo_key', null, [
                'label' => '关键词',
                'help'  => '多个关键词请以逗号","隔开',
            ])
            ->add('seo_description', TextareaType::class, [
                'label'    => '描述',
                'required' => false,
                'attr'     => ['style' => 'resize: none', 'rows' => 4],
            ])
            ->end();
    }

    protected function configureShowFields (ShowMapper $showMapper): void {
        $showMapper
            ->add('id')
            ->add('title')
            ->add('summary')
            ->add('content')
            ->add('thumbnail')
            ->add('is_comment')
            ->add('page_category_id')
            ->add('page_tags')
            ->add('admin_user_id')
            ->add('created_at')
            ->add('updated_at')
            ->add('publish_time')
            ->add('page_view');
    }

    public function getTemplate ($name) {
        switch ($name) {
            case 'list':
                return 'backend/page/list.html.twig';
            case 'edit':
                return 'backend/page/edit.html.twig';
            default:
                return $this->getTemplateRegistry()->getTemplate($name);
        }
    }

    public function prePersist ($object) {
        parent::prePersist($object); // TODO: Change the autogenerated stub

        $object->setAdminUserId($this->security->getUser()->getId());
        $object->setCreatedAt(new \DateTime());

        // 发布状态参数处理
        $this->savePagePublishData($object);
        // 缩略图参数处理
        $this->saveThumbnailData($object);
        // 置顶处理
        if ($object->getIsTop()) {
            GetterHelper::getEntityManager()->getRepository(Page::class)->preTop();
        }
    }

    public function preUpdate ($object) {
        parent::preUpdate($object); // TODO: Change the autogenerated stub

        // 发布状态参数处理
        $this->savePagePublishData($object);
        // 缩略图参数处理
        $this->saveThumbnailData($object);
        // 置顶处理
        if ($object->getIsTop()) {
            GetterHelper::getEntityManager()->getRepository(Page::class)->preTop(true, $object->getId());
        }
    }

    /**
     * 更新缩略图
     * @param $object
     */
    private function saveThumbnailData ($object) {
        $data = $this->getRequest()->get('thumbnail', null);
        if ($data) {
            $object->setThumbnail($data);
        }
    }

    /**
     * 发布状态参数处理
     * @param $object
     * @throws \Exception
     */
    private function savePagePublishData ($object) {
        $data = $this->getRequest()->get('page_publish', []);
        $data['status'] = $data['status'] ?? 'off';
        // 创建
        if ($this->isCurrentRoute('create')) {
            $object->setPublishStatus(($data['status'] == 'on' ? true : false));
            switch ($data['status']) {
                case 'on':
                    if (isset($data['publish_type'])) {
                        $object->setPublishType($data['publish_type']);
                        if ($data['publish_type'] == PageEnum::PUBLISH_TYPE_NOW) {
                            $object->setPublishTime(new \DateTime());
                            $object->setStatus(1);
                        } elseif ($data['publish_type'] == PageEnum::PUBLISH_TYPE_TIMING) {
                            $publish_time = $data['publish_time_date'].' '.$data['publish_time_time'].':00';
                            $object->setPublishTime(new \DateTime($publish_time));
                            $object->setStatus(0);
                        }
                    }
                    break;
                case 'off':
                    $object->setPublishType(null);
                    break;
            }
        }
        // 更新
        if ($this->isCurrentRoute('edit')) {
            $object->setPublishStatus(($data['status'] == 'on' ? true : false));
            switch ($data['status']) {
                case 'on':
                    if (isset($data['publish_type'])) {
                        $object->setPublishType($data['publish_type']);
                        if ($data['publish_type'] == PageEnum::PUBLISH_TYPE_NOW) {
                            $object->setPublishTime(new \DateTime());
                            $object->setStatus(1);
                        } elseif ($data['publish_type'] == PageEnum::PUBLISH_TYPE_TIMING) {
                            $publish_time = $data['publish_time_date'].' '.$data['publish_time_time'].':00';
                            $page_publish_time = $object->getPublishTime()->format('Y-m-d H:i:s');
                            $current_time = date('Y-m-d H:i:s');
                            if ($object->getPublishTime()) {
                                if ($page_publish_time < $publish_time) {
                                    if ($publish_time > $current_time) {
                                        $object->setPublishTime(new \DateTime($publish_time));
                                        $object->setStatus(0);
                                    } else {
                                        $object->setPublishTime(new \DateTime($publish_time));
                                        $object->setStatus(1);
                                    }
                                }
                            }
                        }
                    }
                    break;
                case 'off':
                    $object->setPublishType(null);
                    $object->setPublishTime(null);
                    $object->setStatus(0);
                    break;
            }
        }
    }

    protected function configureRoutes (RouteCollection $collection) {
        parent::configureRoutes($collection); // TODO: Change the autogenerated stub
        $collection->remove('export');
        $collection->remove('show');
    }

    public function createQuery ($context = 'list') {
        $query = parent::createQuery($context); // TODO: Change the autogenerated stub

        $query->andWhere($query->getRootAliases()[0].'.status != -1');

        // 非超级管理员只能查看自己的文章
        if (!$this->security->getUser()->isSuperAdmin()) {
            $query->andWhere(
                $query->expr()->eq($query->getRootAliases()[0].'.admin_user_id', ':admin_user_id')
            );
            $query->setParameter('admin_user_id', $this->security->getUser()->getId());
        }

        return $query;
    }

    public function getObjectMetadata ($object) {
        return new Metadata($object->getTitle(), $object->getSummary(), $object->getThumbnail());
    }

    public function postPersist ($object) {
        parent::postPersist($object);

        // 文章创建成功后给订阅用户发送邮件通知
        $this->bus->dispatch(new SubscribePage($object->getId()));

        // 记录日志
        $description = '标题:['.$object->getTitle().'] ';
        LogHelper::buildLog(LogTypeEnum::TYPE_PAGE_CREATE, $description);
    }

    public function postUpdate ($object) {
        parent::postUpdate($object); // TODO: Change the autogenerated stub

        // 记录日志
        $description = '标题:['.$object->getTitle().'] ';
        $parameter = clone $object;
        $parameter->setContent("");
        LogHelper::buildLog(LogTypeEnum::TYPE_PAGE_UPDATE, $description, $parameter);
    }
}
